import 'dart:math';

import 'package:EZ_Batter/src/tool/assets.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

///LineChar数据源
abstract class LineCharDataSource {
  ///有几条线条，一般默认是一条
  int numbersOfLine() => 1;

  ///返回所有的点
  List<FlSpot> allSpotsForLineInSection(int section);

  ///底坐标文本
  Widget? textForBottomAxis(int section, double value, TitleMeta meta, double chartWidth);

  ///左坐标文本
  Widget? textForLeftAxis(int section, double value, TitleMeta meta, double chartWidth);

  ///右坐标文本
  Widget? textForRightAxis(int section, double value, TitleMeta meta, double chartWidth);
}

///LineChar其他代理
abstract class LineCharDelegate {
  Widget widgetBottomInLineChar() => Container();
  Widget widgetLeftInLineChar() => Container();
  Widget widgetRightInLineChar() => Container();
  Widget widgetTopInLineChar() => Container();

  ///折线条的颜色
  List<Color> colorsForLineBarInSection(int section) => [Colors.red];

  ///折线区域内的颜色
  List<Color> belowColorsForLineBarInSection(int section) => [Colors.red];

  ///触摸在哪个线条上
  void touchForLineBarInSection(FlTouchEvent event, LineTouchResponse? response) {}

  ///自定义y轴对应的刻度上的水平网格是否显示
  bool showHorizontalGridLine(double value) => true;

  ///自定义x轴对应的刻度上的垂直网格是否显示
  bool showVerticalGridLine(double value) => true;

  ///自定义水平网格线条的样式
  FlLine? drawHorizontalGridLine(double value);

  ///自定义垂直网格线条的样式
  FlLine? drawVerticalGridLine(double value);

  ///Y值最大最小范围
  Offset? limitYAxis();

  ///网格最小变化
  double? intervalOfGridYAxis();
}

class LinecharBgView extends StatefulWidget {
  LineCharDataSource dataSource;
  LineCharDelegate delegate;

  LinecharBgView({super.key, required this.dataSource, required this.delegate});

  @override
  State<LinecharBgView> createState() => _LinecharBgViewState();
}

class _LinecharBgViewState extends State<LinecharBgView> {
  List<int> showingTooltipOnSpots = [];
  @override
  void initState() {
    super.initState();
    Future.delayed(const Duration(milliseconds: 100), () {});
  }

  List<LineChartBarData> get lineBarsData {
    return List.generate(widget.dataSource.numbersOfLine(), ($0) {
      List<Color> lineColor = widget.delegate.colorsForLineBarInSection($0);
      List<Color> belowColor = widget.delegate.belowColorsForLineBarInSection($0);
      lineColor =
          lineColor.length <= 1 ? List.filled(2, lineColor.isNotEmpty ? lineColor.first : Colors.red) : lineColor;
      belowColor =
          belowColor.length <= 1 ? List.filled(2, belowColor.isNotEmpty ? belowColor.first : Colors.red) : belowColor;
      List<FlSpot> spot_list = widget.dataSource.allSpotsForLineInSection($0);

      return LineChartBarData(
        showingIndicators: showingTooltipOnSpots,
        spots: spot_list.where((spot) => spot.y != 0.0).toList(), // 过滤掉不达标的点
        isCurved: false,
        barWidth: 1,
        shadow: const Shadow(blurRadius: 0),
        belowBarData: BarAreaData(
          show: false,
          gradient: LinearGradient(colors: belowColor),
        ),
        dotData: const FlDotData(show: false),
        gradient: LinearGradient(
          colors: lineColor,
          // stops: const [0.1, 0.2],
        ),
      );
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    final tooltipsOnBar = lineBarsData[0];

    return Container(
      padding: const EdgeInsets.only(left: 10, right: 10, bottom: 0),
      child: Container(
        decoration: BoxDecoration(borderRadius: BorderRadius.circular(8), color: Color_Line_bg),
        child: LayoutBuilder(builder: (context, constraints) {
          return LineChart(
            LineChartData(
              ///lineBarsData
              lineBarsData: lineBarsData,
              minY: widget.delegate.limitYAxis()?.dx ?? 0,
              maxY: widget.delegate.limitYAxis()?.dy ?? 1,
              minX: 0,
              maxX: 99,

              // 右侧 Y 轴的范围（通过 extraLinesData 实现）
              // extraLinesData: ExtraLinesData(horizontalLines: [
              //   HorizontalLine(y: 10.8, color: Colors.transparent), // 用于标定最大 Y 值
              //   HorizontalLine(y: 9, color: Colors.transparent), // 用于标定最小 Y 值
              // ]),

              ///FlTitlesData。上下左右的轴上的文本，名称
              titlesData: FlTitlesData(
                ///top
                topTitles: AxisTitles(
                  axisNameWidget: widget.delegate.widgetTopInLineChar(),
                  axisNameSize: 24,
                  sideTitles: SideTitles(
                    showTitles: true,
                    interval: 1,
                    getTitlesWidget: (value, meta) => Container(),
                    reservedSize: 10,
                  ),
                ),

                ///bottom
                bottomTitles: AxisTitles(
                  axisNameWidget: widget.delegate.widgetBottomInLineChar(),
                  axisNameSize: 30,
                  sideTitles: SideTitles(
                    showTitles: true,
                    interval: 1,
                    reservedSize: 30,
                    getTitlesWidget: (value, meta) => SideTitleWidget(
                        axisSide: meta.axisSide,
                        child:
                            widget.dataSource.textForBottomAxis(0, value, meta, constraints.maxWidth) ?? Container()),
                  ),
                ),

                ///left
                leftTitles: AxisTitles(
                  axisNameWidget: widget.delegate.widgetLeftInLineChar(),
                  axisNameSize: 1,
                  sideTitles: SideTitles(
                    showTitles: true,
                    interval: 0.01, //控制间隔，左边的Y轴刻度最小颗粒度。通过"textForLeftAxis"控制y轴上的刻度显示
                    reservedSize: 35,
                    getTitlesWidget: (value, meta) => SideTitleWidget(
                        axisSide: meta.axisSide,
                        child: widget.dataSource.textForLeftAxis(0, value, meta, constraints.maxWidth) ?? Container()),
                  ),
                ),

                ///right
                rightTitles: AxisTitles(
                  axisNameWidget: widget.delegate.widgetRightInLineChar(),
                  axisNameSize: 1,
                  sideTitles: SideTitles(
                    showTitles: true,
                    interval: 0.01, //控制间隔，右边的Y轴刻度最小颗粒度。通过"textForLeftAxis"控制y轴上的刻度显示
                    reservedSize: 35,
                    getTitlesWidget: (value, meta) => SideTitleWidget(
                        axisSide: meta.axisSide,
                        child: widget.dataSource.textForRightAxis(0, value, meta, constraints.maxWidth) ?? Container()),
                  ),
                ),
              ),

              ///FlGridData。网格
              gridData: FlGridData(
                show: true,
                drawVerticalLine: true,
                drawHorizontalLine: true,
                horizontalInterval: max(widget.delegate.intervalOfGridYAxis() ?? 0.1,
                    0.1), //网格颗粒度越细，widget.delegate.drawHorizontalGridLine就能越精细控制
                verticalInterval: 10,
                getDrawingHorizontalLine: (value) {
                  return widget.delegate.drawHorizontalGridLine(value) ??
                      const FlLine(color: Colors.grey, strokeWidth: 0.5, dashArray: [2, 2]);
                },
                getDrawingVerticalLine: (value) {
                  return widget.delegate.drawVerticalGridLine(value) ??
                      const FlLine(color: Colors.grey, strokeWidth: 0.5, dashArray: [2, 2]);
                },
                checkToShowHorizontalLine: (value) {
                  return widget.delegate.showHorizontalGridLine(value);
                },
                checkToShowVerticalLine: (value) {
                  return widget.delegate.showVerticalGridLine(value);
                },
              ),

              // 这个保证不会超出 minY~maxY 之外
              clipData: const FlClipData.all(),

              ///FlBorderData。边框
              borderData: FlBorderData(show: true, border: Border.all(color: Colors.grey)),
              showingTooltipIndicators: showingTooltipOnSpots.map((index) {
                return ShowingTooltipIndicators(
                    [LineBarSpot(tooltipsOnBar, lineBarsData.indexOf(tooltipsOnBar), tooltipsOnBar.spots[index])]);
              }).toList(),

              ///LineTouchData
              lineTouchData: LineTouchData(
                enabled: true,
                handleBuiltInTouches: false,
                touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
                  if (response == null || response.lineBarSpots == null) {
                    return;
                  }
                  if (event is FlTapUpEvent) {
                    final spotIndex = response.lineBarSpots!.first.spotIndex;
                    setState(() {
                      if (showingTooltipOnSpots.contains(spotIndex)) {
                        showingTooltipOnSpots.remove(spotIndex);
                      } else {
                        showingTooltipOnSpots.add(spotIndex);
                      }
                    });
                    widget.delegate.touchForLineBarInSection(event, response);
                  }
                },
                mouseCursorResolver: (FlTouchEvent event, LineTouchResponse? response) {
                  if (response == null || response.lineBarSpots == null) {
                    return SystemMouseCursors.basic;
                  }
                  return SystemMouseCursors.click;
                },

                ///touch 折线到触点，最大值到最小值 的 竖线的连线
                getTouchedSpotIndicator: (LineChartBarData barData, List<int> spotIndexes) {
                  return spotIndexes.map((index) {
                    return TouchedSpotIndicatorData(
                      ///连线
                      const FlLine(
                        color: Colors.transparent,
                        strokeWidth: 1,
                      ),
                      FlDotData(
                        show: true,
                        getDotPainter: (spot, percent, barData, index) => FlDotCirclePainter(
                          radius: 2,
                          color: lerpGradient(
                            barData.gradient?.colors ?? [Colors.red],
                            barData.gradient?.stops ?? [1.0],
                            percent / 100,
                          ),
                          strokeWidth: 1,
                          strokeColor: Colors.white,
                        ),
                      ),
                    );
                  }).toList();
                },

                ///touchtip。泡泡框背景
                touchTooltipData: LineTouchTooltipData(
                  getTooltipColor: (touchedSpot) => Colors.yellow,
                  tooltipMargin: 10,
                  maxContentWidth: 100,
                  tooltipPadding: const EdgeInsets.all(5),
                  tooltipRoundedRadius: 4,
                  getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
                    return lineBarsSpot.map((lineBarSpot) {
                      return null; //不显示气泡提示
                      // return LineTooltipItem(
                      //     lineBarSpot.x.toString(), const TextStyle(color: Colors.white, fontSize: 12));
                    }).toList();
                  },
                ),
              ),
            ),
          );
        }),
      ),
    );
  }
}

Color lerpGradient(List<Color> colors, List<double> stops, double t) {
  if (colors.isEmpty) {
    throw ArgumentError('"colors" is empty.');
  } else if (colors.length == 1) {
    return colors[0];
  }

  if (stops.length != colors.length) {
    stops = [];

    /// provided gradientColorStops is invalid and we calculate it here
    colors.asMap().forEach((index, color) {
      final percent = 1.0 / (colors.length - 1);
      stops.add(percent * index);
    });
  }

  for (var s = 0; s < stops.length - 1; s++) {
    final leftStop = stops[s];
    final rightStop = stops[s + 1];
    final leftColor = colors[s];
    final rightColor = colors[s + 1];
    if (t <= leftStop) {
      return leftColor;
    } else if (t < rightStop) {
      final sectionT = (t - leftStop) / (rightStop - leftStop);
      return Color.lerp(leftColor, rightColor, sectionT)!;
    }
  }
  return colors.last;
}
